package org.amj.wn;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import org.amj.wn.SchemaItem.UIOptions;
import org.amj.wn.sect.SectWaqfeNau;


import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.FetchOptions;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.PropertyProjection;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.Query.CompositeFilter;
import com.google.appengine.api.datastore.Query.CompositeFilterOperator;
import com.google.appengine.api.datastore.Query.Filter;
import com.google.appengine.api.datastore.Query.FilterOperator;
import com.google.appengine.api.datastore.Query.FilterPredicate;

public class WaqfeNau {
	private static final ObjectSchema schema = new ObjectSchema();
	private static final String ENTITY_NAME = "WaqfeNou";
	private static final String PARENT_ENTITY_NAME = "AMJ";
	private final Entity result; 



	static {

		Property[] values = Property.values();

		for (Property property : values) {
			property.addToSchema(schema);
		}
	}

	public WaqfeNau(Entity result) {
		this.result = result;
	}

	public Object getProperty(Property property) {
		return result.getProperty(property.toString());
	}

	public void setProperty(Property property, Object value) {
		result.setProperty(property.toString(), value);
	}

	public Entity getResult() {
		return result;
	}

	public static ObjectSchema getSchema() {
		return schema;
	}

	public static WaqfeNau get(String memberCode) {

		WaqfeNau wn = null;

		DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
		Filter memberCodeFilter = new FilterPredicate(Property.memberCode.toString(),
				FilterOperator.EQUAL, memberCode);

		Query q = new Query(ENTITY_NAME, parentKey()).setFilter(memberCodeFilter);

		PreparedQuery pq = datastore.prepare(q);

		List<Entity> resultList = pq.asList(FetchOptions.Builder.withLimit(1));

		Entity result = null;

		if(resultList != null && resultList.size() > 0) {
			result = resultList.get(0);
			wn = new WaqfeNau(result);
		} else {
			wn = null;
		}

		return wn;
	}



	public static boolean createOrUpdate(String memberCode, String passCode, String jamaatCode) {

		WaqfeNau waqfeNau = get(memberCode);


		if(waqfeNau == null) {
			waqfeNau = new WaqfeNau(new Entity(ENTITY_NAME, parentKey()));
		}

		waqfeNau.setProperty(Property.memberCode, memberCode);
		waqfeNau.setProperty(Property.passCode, passCode);
		waqfeNau.setProperty(Property.jamaatCode, jamaatCode);
		

		return waqfeNau.save();
	}

	public static boolean modify(String memberCode, Map<String, String> properties) {

		WaqfeNau waqfeNau = get(memberCode);
		if(waqfeNau == null)
			return false;

		for (Map.Entry<String, String> entry : properties.entrySet()) {

			Property value = getPropertyEntry(entry);
			if(value != null)
				waqfeNau.setProperty(value, entry.getValue());
		}

		return waqfeNau.save();

	}
	
	public static boolean scopedModify(String sectId, String memberCode, Map<String, String> properties) {

	    SectWaqfeNau sectWaqfeNau = SectWaqfeNau.get(sectId);
	    if(sectWaqfeNau == null)
	    	return false;
		
		WaqfeNau waqfeNau = get(memberCode);
		if(waqfeNau == null)
			return false;
		
		if(waqfeNau.getProperty(Property.jamaatCode) == null || !waqfeNau.getProperty(Property.jamaatCode).equals(sectWaqfeNau.getJamaat()))
			return false;

		for (Map.Entry<String, String> entry : properties.entrySet()) {

			Property value = getPropertyEntry(entry);
			if(value != null)
				waqfeNau.setProperty(value, entry.getValue());
		}

		return waqfeNau.save();

	}

	private static Property getPropertyEntry(Map.Entry<String, String> entry) {
		try {
			return Property.valueOf(entry.getKey());
		} catch(Exception exp) {
			return null;
		}
	}

	private boolean save() {
		DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();

		for(Property pr : Property.values()) {
			Object property = result.getProperty(pr.name());
			if(pr.getUiElement() == UIElement.FIELD && pr.getUiOption() != UIOptions.hidden && property instanceof String) {
				
				if(property == null)
					property = "";
					
				result.setProperty(normalizePropertyName(pr), property.toString().toUpperCase());
			}
		}
		
		datastore.put(result);
		return true;
	}

	private static String normalizePropertyName(Property pr) {
		return pr.name() + "_UPPER";
	}

	public static void delete(String memberCode) {
		WaqfeNau waqfeNau = get(memberCode);
		waqfeNau.delete();

	}
	
	private static Key parentKey() {
		return KeyFactory.createKey(PARENT_ENTITY_NAME, "waqfeen");
	}

	private void delete() {
		DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
		datastore.delete(result.getKey());
	}

	public String getPassCode() {
		return getProperty(Property.passCode).toString();
	}

	public String getMemberCode() {
		return getProperty(Property.memberCode).toString();
	}

	public String getGreetingName() {
		Object name = getProperty(Property.firstName);
		return name == null ? getMemberCode() : name.toString();
	}
	
	
	public static List<Entity> scopedSearch(String sectId, int startIndex, int pageSize, String property, String operator, String value
			, String property2, String operator2, String value2) {
	    Query query = new Query(ENTITY_NAME, parentKey());
	    
		Filter finalFilter = null;
	    if(!"".equals(property) && property != null) {
	    	Property prop = Property.valueOf(property);
			String normalizePropertyName = normalizePropertyName(prop);
			Filter filterPredicate = createFilter(operator, value, normalizePropertyName);
			if(!"".equals(property2) && property2 != null) {
				
				finalFilter = new CompositeFilter(CompositeFilterOperator.AND, Arrays.<Filter>asList(
						filterPredicate,
						createFilter(operator2, value2, normalizePropertyName(Property.valueOf(property2)))
						)); 
				
			} else {
				finalFilter = filterPredicate;
			}
			
	    	query.addSort(normalizePropertyName, Query.SortDirection.DESCENDING);
	    } else {
	    	query.addSort(Property.memberCode.toString(), Query.SortDirection.ASCENDING);
	    }

	    SectWaqfeNau sectWaqfeNau = SectWaqfeNau.get(sectId);
	    if(sectWaqfeNau == null)
	    	return Collections.emptyList();
	    
	    Filter sectFilter = new FilterPredicate(Property.jamaatCode.name(), FilterOperator.EQUAL, sectWaqfeNau.getJamaat());
	    
	    if(finalFilter == null)
	    	finalFilter = sectFilter;
	    else {
			finalFilter = new CompositeFilter(CompositeFilterOperator.AND, Arrays.<Filter>asList(
					sectFilter,
					finalFilter
					)); 
	    }
	    
	    query.setFilter(finalFilter);
	    
		
	    DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
	    return datastore.prepare(query).asList(FetchOptions.Builder.withLimit(pageSize).offset(startIndex));

	}

	public static List<Entity> search(int startIndex, int pageSize, String property, String operator, String value
			, String property2, String operator2, String value2) {
	    Query query = new Query(ENTITY_NAME, parentKey());
	    
	    if(!"".equals(property) && property != null) {
	    	Property prop = Property.valueOf(property);
			String normalizePropertyName = normalizePropertyName(prop);
			Filter finalFilter = null;
			Filter filterPredicate = createFilter(operator, value, normalizePropertyName);
			if(!"".equals(property2) && property2 != null) {
				
				finalFilter = new CompositeFilter(CompositeFilterOperator.AND, Arrays.<Filter>asList(
						filterPredicate,
						createFilter(operator2, value2, normalizePropertyName(Property.valueOf(property2)))
						)); 
				
			} else {
				finalFilter = filterPredicate;
			}
			
			query.setFilter(finalFilter);
	    	query.addSort(normalizePropertyName, Query.SortDirection.DESCENDING);
	    } else {
	    	query.addSort(Property.memberCode.toString(), Query.SortDirection.ASCENDING);
	    }
	    
		
	    DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
	    return datastore.prepare(query).asList(FetchOptions.Builder.withLimit(pageSize).offset(startIndex));

	}

	private static Filter createFilter(String operator, String value,
			String normalizePropertyName) {
		
		FilterOperator filterOperator = FilterOperator.valueOf(operator);
		Filter filterPredicate = new FilterPredicate(normalizePropertyName, filterOperator, value == null ? "" : value.toUpperCase());
		
		if(filterOperator == FilterOperator.EQUAL && isNullOrEmpty(value)) {
			new CompositeFilter(CompositeFilterOperator.OR, Arrays.<Filter>asList(
					filterPredicate,
					new FilterPredicate(normalizePropertyName, filterOperator, null)
					)); 
		} 
		
		return filterPredicate;
	}

	private static boolean isNullOrEmpty(String value) {
		
		return "".equals(value) || value == null;
	}
}
